const ncname = `[a-zA-Z_][\\-\\.0-9_a-zA-Z]*`; // 标签名 
const qnameCapture = `((?:${ncname}\\:)?${ncname})`; //  用来获取的标签名的 match后的索引为1的
const startTagOpen = new RegExp(`^<${qnameCapture}`); // 匹配开始标签的 
const endTag = new RegExp(`^<\\/${qnameCapture}[^>]*>`); // 匹配闭合标签的
//           aa  =   "  xxx "  | '  xxxx '  | xxx
const attribute = /^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/; // a=b  a="b"  a='b'
const startTagClose = /^\s*(\/?)>/; //     />   <div/>

import generate from './generate.js'

function compilerToFunction(template){

    root=null  //根标签
    stack=[] 
    
    let ast=parseHtml(template)
    console.log(ast,'ast语法树')
    //在将ast转成字符串，传给render函数执行
    let code=generate(ast)
    console.log('生成的render字符串----',code)
    let render=new Function(`with(this){return ${code}}`)
    return render
}

function parseHtml(html){
    //更新截取已经解析过的html模板
    function advance(index){
        html=html.slice(index)
    } 
    //匹配开始标签  
    function parseStartTag(){
       let start=html.match(startTagOpen)
       if(start){
           //需要返回标签的名称和属性 <div id='10' a=2>
           let match={
               tagName:start[1],
               attrs:[]
           }
           advance(start[0].length)
           let end,attr
           while (!(end=html.match(startTagClose))&&(attr=html.match(attribute))) {
               //当不是结束标签符号> 时，且有属性
               //匹配到一个属性就会执行
               //属性值可能是单引号3/双引号4/没有引号5/没写属性值默认为true
               match.attrs.push({name:attr[1],value:attr[3]||attr[4]||attr[5]||true})
               advance(attr[0].length)
           }
           if(end){
             advance(end[0].length)
           } 
           return match
       }
       return false
    }

    //循环截取匹配html
    while (html) {
        let textEnd=html.indexOf('<')  //匹配开始标签的位置
        if(textEnd==0){
            let startTagMatch=parseStartTag(html)  //开始标签,返回的是ast对象
            if(startTagMatch){
               start(startTagMatch.tagName,startTagMatch.attrs)
               continue
            }

            //结束标签  >
            let endTagMath=html.match(endTag)
            if(endTagMath){
                end(endTagMath[1])
                advance(endTagMath[0].length)
                continue
            }
        }

        //文本内容时
        let text=null
        if(textEnd>0){    //  数据{{name}}<span>....
          text=html.substring(0,textEnd)  //截取文本部分
        }
        if(text){
            chars(text)
            advance(text.length)
        }
    }
    return root  //返回ast对象
}
let root=null  //根标签
let stack=[]   //储存解过程中的标签父子关系栈
function start(tagName,attrs){
   let parent=stack[stack.length-1]
   let element=createAstElement(tagName,attrs)
   if(!root){
       root=element
   }
   if(parent){
       element.parent=parent   
       parent.children.push(element)  //当前元素就是为栈中上一元素的子标签
   }

   stack.push(element)   //将收集到的开始标签名存入栈中
}
function end(tagName){
   let last=stack.pop()  //将栈中存储的标签弹出
   if(last.tag!==tagName){
       throw new Error('标签没有闭合')
   }
}
function chars(text){
    text=text.replace(/\s+/g,'')
    let parent=stack[stack.length-1]
    if(text){
        //添加文本节点
        parent.children.push({
            type:3,
            text
        })
    }
}

function createAstElement(tagName,attrs){
    //生成ast 语法结构
    return {
        tag:tagName,
        type:1,
        children:[],
        attrs
    }
}






export default compilerToFunction